home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
289_01
/
buildlvl.c
< prev
next >
Wrap
Text File
|
1989-05-23
|
14KB
|
431 lines
/*-----------------------------------------------------------------------------
Build the tree of moves down to a given level.
Revision History
----------------
NAME DATE MODS
Gary Culp 19 Dec 1988 -
2 Jan 1988 Initial version
-----------------------------------------------------------------------------*/
#include <stdio.h>
#include "othello.h"
STATIC int after_opponents_move(move_type humans_move);
STATIC void build_children_of_a_board(
key_type parent_limb_key,
key_type parent_board_key,
unsigned char movers_color);
STATIC int build_a_level(void);
/* return values from build_a_level() */
#define BT_COMPLETED 0
#define BT_DBFULL 1
/*
This level:
board/limb has children? is bottom?
-------------------------------------
-limb----------n--------------n------------ERROR
-limb----------n------------y--------------ERROR
limb y n descend along each child
limb y y return
board n n build children
board n y return
-board-------y----------------n------------ERROR
board y y return
*/
/*
Keep track of the depth to which the tree has been fully built.
*/
STATIC int tree_depth = 0;
/*
The build_tree function is iterative rather than recursive because building the
tree is asynchronous to the human's move; and we want to take advantage of
information about the human's move immediately (by pruning moves he didn't
make from the tree).
Information for manually-recursive tree build:
'stack' of limb keys
desired depth (actually use value of stack index at desired depth; which
turns out to be the desired depth - 2)
stack pointer for stack of limb keys (actually an index rather than
a pointer)
mover's color at current depth
*/
STATIC key_type limb_key_stack[BT_MAX_DEPTH];
STATIC int bt_desired_nest;
STATIC int bt_current_nest; /* "stack pointer" (index) for limb_key_stack */
STATIC unsigned char bt_movers_color;
STATIC int human_state;
/* defines for human_state */
#define HS_NOT_HUMANS_TURN 0
#define HS_WAITING_FOR_HUMAN 1
#define HS_HUMAN_MOVED 2
STATIC humans_move_limb_key;
/*
Build the tree to the specified level
The function builds the tree until it reaches the specified depth, or
the database fills up.
If movers_color == THEM_PIECE:
The function will also check for input from the human player while it is
building the tree. If it has to stop building the tree, it will continue
to check for the human's input. It will not return until the human player
has input his move.
If movers_color == US_PIECE:
The function will not check for input from the human player.
This function assumes that the root of the tree corresponds to the current
state of the board.
Returns:
depth to which tree was completely built
*/
int
build_tree(int depth_to_build, unsigned char movers_color)
{
struct limb_struct far *limb_ptr;
int temp;
if (movers_color == THEM_PIECE) {
human_state = HS_WAITING_FOR_HUMAN;
depth_to_build++; /* We'll delete 1 level after the human moves; so we
build an extra level now. */
}
else {
human_state = HS_NOT_HUMANS_TURN;
}
limb_ptr = db_retrieve_limb(curnt_top_limb);
if (limb_ptr->move & BOARD_MASK) {
/* The root is a board. There is a lower-level function
(after_opponents_move()) which assumes that the root is not a board,
so we have to build the first level of the tree before continuing.
*/
build_children_of_a_board(curnt_top_limb,
limb_ptr->bc.board_key,
movers_color);
tree_depth = 1;
}
for (bt_desired_nest = tree_depth - 1;
bt_desired_nest <= depth_to_build - 2;
bt_desired_nest++)
{
limb_key_stack[0] = limb_ptr->bc.child_key;
bt_current_nest = 0;
bt_movers_color = movers_color ^ (US_PIECE | THEM_PIECE);
/* Try to build a level. If the database fills up but we're waiting for
input from the human, keep trying to build until we get his input.
*/
do {
temp = build_a_level();
} while (temp != BT_COMPLETED && human_state == HS_WAITING_FOR_HUMAN);
if (temp == BT_COMPLETED) {
tree_depth = bt_desired_nest + 2;
}
else {
break;
}
}
/* We may finish building the tree to the depth we desire before the
human opponent enters his move. If this happens, this loop will wait
for him to enter his move.
*/
while (human_state == HS_WAITING_FOR_HUMAN) {
move_type humans_move;
if ((humans_move = check_for_input()) != HASNT_MOVED) {
human_state = HS_HUMAN_MOVED;
after_opponents_move(humans_move);
}
}
if (movers_color == THEM_PIECE) {
free_limb(curnt_top_limb); /* delete root limb */
/* Make limb for human's move the new root limb */
curnt_top_limb = humans_move_limb_key;
tree_depth--; /* Since we deleted the old root, the tree is shallower */
}
return (tree_depth);
}
/*
Build another level onto the tree
This function communicates through static variables.
Returns:
BT_COMPLETED: finished building the level
BT_DBFULL: had to stop building because database was almost full
*/
STATIC int
build_a_level()
{
limb_type far *limb_ptr;
move_type humans_move;
while (1) { /* exit from loop by 'return's */
if (human_state == HS_WAITING_FOR_HUMAN &&
(humans_move = check_for_input()) != HASNT_MOVED)
{
human_state = HS_HUMAN_MOVED;
if (after_opponents_move(humans_move)) {
return (BT_COMPLETED);
}
}
/*
If the database is almost full, stop building.
Resume build at this point later on, after the tree has been trimmed.
*/
if (db_almost_full()) {
return (BT_DBFULL);
}
/* Limbs have either a board or children.
If this limb has a board, build its children now.
*/
limb_ptr = db_retrieve_limb(limb_key_stack[bt_current_nest]);
if (limb_ptr->move & BOARD_MASK) { /* it's a board */
build_children_of_a_board(limb_key_stack[bt_current_nest],
limb_ptr->bc.board_key,
bt_movers_color);
}
/*
Figure out next limb key to examine (leave on top of limb_key_stack)
*/
if (bt_current_nest != bt_desired_nest) {
/* Follow child key to nest down one level */
limb_key_stack[bt_current_nest + 1] =
db_retrieve_limb(limb_key_stack[bt_current_nest])->bc.child_key;
++bt_current_nest;
bt_movers_color ^= (US_PIECE | THEM_PIECE);
}
else {
while (bt_current_nest >= 0) { /* also contains a 'break' */
/*
Replace limb key on top of stack with its next sibling;
if it has no next sibling, pop it off the stack.
*/
if (
(limb_key_stack[bt_current_nest] =
db_retrieve_limb(limb_key_stack[bt_current_nest])->sibling_key
)
== NO_KEY
)
{
--bt_current_nest; /* pop stack */
bt_movers_color ^= (US_PIECE | THEM_PIECE);
}
else {
break; /* exit from loop */
}
}
if (bt_current_nest < 0) {
/* a complete level of the tree has been built */
return (BT_COMPLETED);
}
}
}
}
/*
Build all the child boards for a given parent_limb.
The parent_limb must have a board (not child limbs) associated with it.
*/
STATIC void
build_children_of_a_bo